#!/usr/bin/envpython
# -*-coding:UTF-8-*-
'''
@File    :   redis_lock_hple.py
@Contact :   308711822@qq.com
@License :   (C) Copyright 2021-2225, Personal exclusive right.

@Modify Time      @Author    @Version    @Desciption
------------      -------    --------    -----------
2023/6/9 9:53   小钟同学      1.0         None
'''
import multiprocessing

import redis
import time
import os
import fcntl


class SafeRandom:
    def __init__(self):
        self.file = open('/dev/urandom', 'rb')

    def __del__(self):
        self.file.close()

    def get_bytes(self, num_bytes):
        if os.name == 'posix':
            try:
                fcntl.flock(self.file.fileno(), fcntl.LOCK_EX | fcntl.LOCK_NB)
            except IOError:
                raise Exception("Couldn't acquire lock on /dev/urandom")
        return self.file.read(num_bytes)


def generate_token(num_bytes=16):
    rand = SafeRandom()
    return rand.get_bytes(num_bytes).hex()


class Lock(object):
    def __init__(self, lockname, timeout=10):
        self.lockname = lockname
        self.timeout = timeout
        self.identifier = generate_token()
        self.acquired = False
        self.redis = redis.Redis(host='localhost', port=6379)

    def acquire(self):
        ret = self.redis.set(self.lockname, self.identifier, nx=True, ex=self.timeout)
        if ret:
            self.acquired = True
        return ret

    def heartbeat(self):
        return self.redis.set(self.lockname, self.identifier, ex=self.timeout, xx=True)

    def __enter__(self):
        while True:
            ret = self.acquire()
            if ret:
                break
            elif not self.redis.ttl(self.lockname):
                self.redis.set(self.lockname, self.identifier, ex=self.timeout)
            time.sleep(0.1)
        return self

    def __exit__(self, exc_type, exc_value, traceback):
        if self.acquired:
            self.redis.delete(self.lockname)
        else:
            self.heartbeat()
        return False


import redis
import time


redis_client = redis.Redis(host="localhost", port=6379)
counter_name = "my_counter"

def increase_counter(num_times):
   with Lock(counter_name):
       for _ in range(num_times):
           value = redis_client.get(counter_name)
           value = int(value) if value else 0
           value += 1
           redis_client.set(counter_name, value)

if __name__ == "__main__":
   num_processes = 3
   num_times = 10000

   processes = []

   for i in range(num_processes):
       process = multiprocessing.Process(target=increase_counter, args=(num_times,))
       process.start()
       processes.append(process)

   for process in processes:
       process.join()

   print(f"Counter value: {redis_client.get(counter_name)}")
